<?php
class Zen_Controller_Action_Helper_Jstree extends Zend_Controller_Action_Helper_Abstract {
	/**
	 * Suppress exit when sendJson() called
	 * @var boolean
	 */
	public $suppressExit = false;

	/**
	 * Create JSON response
	 *
	 * Encodes and returns data to JSON. Content-Type header set to
	 * 'application/json', and disables layouts and viewRenderer (if being
	 * used).
	 *
	 * @param  mixed   $data
	 * @param  boolean $keepLayouts
	 * @param  boolean|array $keepLayouts
	 * NOTE:   if boolean, establish $keepLayouts to true|false
	 * if array, admit params for Zend_Json::encode as enableJsonExprFinder=>true|false
	 * if $keepLayouts and parmas for Zend_Json::encode are required
	 * then, the array can contains a 'keepLayout'=>true|false
	 * that will not be passed to Zend_Json::encode method but will be passed
	 * to Zend_View_Helper_Json
	 * @throws Zend_Controller_Action_Helper_Json
	 * @return string
	 */
	public function encodeJson($data, $keepLayouts = false) {
		/**
		 * @see Zend_View_Helper_Json
		 */
		require_once 'Zend/View/Helper/Json.php';
		$jsonHelper = new Zend_View_Helper_Json ();
		$data = $jsonHelper->json ( $data, $keepLayouts );

		if (! $keepLayouts) {
			/**
			 * @see Zend_Controller_Action_HelperBroker
			 */
			require_once 'Zend/Controller/Action/HelperBroker.php';
			Zend_Controller_Action_HelperBroker::getStaticHelper ( 'viewRenderer' )->setNoRender ( true );
		}

		return $data;
	}

	/**
	 * Encode JSON response and immediately send
	 *
	 * @param  mixed   $data
	 * @param  boolean|array $keepLayouts
	 * NOTE:   if boolean, establish $keepLayouts to true|false
	 * if array, admit params for Zend_Json::encode as enableJsonExprFinder=>true|false
	 * if $keepLayouts and parmas for Zend_Json::encode are required
	 * then, the array can contains a 'keepLayout'=>true|false
	 * that will not be passed to Zend_Json::encode method but will be passed
	 * to Zend_View_Helper_Json
	 * @return string|void
	 */
	public function sendJson($data, $keepLayouts = false) {
		$data = $this->encodeJson ( $data, $keepLayouts );
		$response = $this->getResponse ();
		$response->setBody ( $data );

		if (! $this->suppressExit) {
			$response->sendResponse ();
			exit ();
		}

		return $data;
	}

	protected function prepareData($data, $attrColumns = false) {
		$children = array ();
		foreach ( $data as $basenode ) {
			$node = array ();
			$node ['data'] = $basenode ['label'];
			$node ['attr'] = array ();
			$node ['attr'] ['id'] = 'item_' . $basenode ['id'];
			$node ['attr'] ['rel'] = $basenode ['type'];
			if (isset($basenode['active'])) {
				$node ['attr']['active'] = $basenode['active'];
			}
			if ($attrColumns != false) {
				foreach ( $basenode as $field => $value ) {
					if (in_array ( $field, $attrColumns )) {
						$node ['attr'] [$field] = $value;
					}
				}
			}

			$node ['state'] = ($basenode ['right'] - $basenode ['left'] > 1) ? "closed" : "";
			$children [] = $node;
		}
		return $children;
	}
	
	public function log($message, $priority = null, $params = null) {
    	if (! $params)  $params = array();
    	$model = $this->model;
    	if ($model->isAllowLog()) 
    		$params['addition'] = serialize( $this->params );
    	if (! $priority) 	$priority = Zend_Log::NOTICE;
    	$params['resource'] = $model->getTableName();
    	Log_Model_Logger::log($message, $priority, $params);
    	return $this;
    }

	public function direct($model, $params, $sendNow = true, $keepLayouts = false) {
		$this->params = $params;
		$this->model = $model;
		$operation = $params ['operation'];
		unset ( $params ['operation'] );
		$data = array ('status' => 0 );
		$controler = $this->getActionController();
		switch ($operation) {
			case 'get_children' :
				{
					$data = $this->_getChildren();
					break;
				}
			case 'create' :
				{
					$keepLayouts = true;
					$sendNow = false;
					$this->_createNode();
					break;
				}
			case 'update' :
				{
					$types = $model->getTypes ();
					$keepLayouts = true;
					$sendNow = false;

					if (! isset ( $params ['type'] )) {
						throw new Zend_Exception ( 'Dont set type parametr' );
					}

					if (! isset ( $params ['id'] )) {
						throw new Zend_Exception ( 'Dont set id parametr' );
					}
					$id = preg_replace ( '/\D/', '', $params ['id'] );
					$form_name = $types [$params ['type']] ['form'];
					$form_options['attribs'] = array( 'id'=> $id, 'parent_id'=>null);
					$form = new $form_name ($form_options);

					$title = 'Редактировать ' . $types [$params ['type']] ['label'];
					
					if (! $controler->getRequest ()->isPost ()) {
						$ItemModel = $types [$params ['type']] ['model'];

						$item = $ItemModel->read ( "`id`='" . $id . "'" );
						$tree_item = $model->read($id);
						
						$item = array_merge($tree_item, $item);
						
						if ($item) {
							$form->setDefaults ( $item );
						} else {
							throw new Zend_Exception ( 'Cant find item with id=' . $id );
						}
					}

					if ($controler->getRequest ()->isPost () && $form->isValid ( $params )) {
						$formParams = $form->getValues ();
						//Если несколько субформ
						if (sizeof ( $form->getSubForms () ) > 0) {
							$data = array ();
							foreach ( $form->getSubForms () as $subform ) {
								$data = array_merge ( $data, $formParams [$subform->getName ()] );
							}
							$formParams = $data;
						}
						$formParams ['type'] = $params ['type'];
						$model->update ( $id, $formParams );
						$this->log('Updating ' . $id . ' ' . $types [$params ['type']] ['label']);
						
						$data = array ('status' => true, 'id' => $id, 'label' => $params ['label'] );
					
						$controler->getHelper('flashMessenger')->setNamespace ( 'messages' )->addMessage ( array ('text' => 'Обновление выполнено успешно', 'type' => $type ) );
						$module_name = $this->getRequest()->getModuleName();
						$controler_name = $this->getRequest()->getControllerName();
						$controler->getHelper('redirector')->gotoRoute(array('module'=>$module_name,'controller'=>$controler_name,'action'=>'index'),'backend');
					} else {
						$this->getActionController ()->view->form = $form;
						$view = $types [$params ['type']] ['view'];
						$controler->view->title = $title;
						$controler->render ( $view );
					}
					break;
				}
			case 'rename_node' :
				{
					$prms = array ('label' => $params ['label'] );
					foreach ( $params as $key => $param ) {
						if (preg_match ( '/^attr_/', $key )) {
							$prms [$key] = $param;
						}
					}
					$status = $model->update ( $params ['id'], $prms );
					$data = array ('status' => $status );
					break;
				}
			case 'delete_node' :
				{
					$id = $params ['id'];
					$status = $model->delete ( $id );
					$this->log('Deleting ' . $id . ' ' . $types [$params ['type']] ['label']);
					$data = array ('status' => $status );
					break;
				}
			case 'reorder' :
				{
					$id = $params ['id'];
					$objectiveNodeId = $params ['objectiveNodeId'];
					$position = $params ['position'];
					$parent_id = $params ['parent_id'];
					$pos = $params ['pos'];
					$status = $model->reorder ( $id, $objectiveNodeId, $position, $pos, $parent_id );
					$data = array ('status' => $status );
					break;
				}
			default :
				{
					break;
				}
		}
		if ($sendNow) {
			return $this->sendJson ( $data, $keepLayouts );
		} else {
			return $data;
		}
	}
	
	private function _getChildren() {
		$params = $this->params;
		$model = $this->model;
		$types = $model->getTypes ();
		$select = $model->select ();
		$columns = array('tree'=>array('id','type','left','right'));
		foreach ( $select->getTypes () as $type => $table ) {
			if ($type != 'tree' && $type != 'core') {
				$columns [$type] = array ('label' );
			}
			if (isset($types[$type]['active_state']) && $types[$type]['active_state'] == true) {
				$columns ['tree'][] = 'active';
			}
		}
		$grid = $model->getGrid ();
		$attribColumns = false;
		if ($grid) {
			$attribColumns = array ();
			foreach ( $grid ['types'] as $type ) {
				if (! isset ( $columns [$type] )) {
					$columns [$type] = array ();
				}
				foreach ( $grid ['columns'] as $column ) {
					if (isset ( $column ['value'] )) {

						if (! in_array ( $column ['value'], $columns [$type] )) {
							$columns [$type] [] = $column ['value'];
							$attribColumns [] = $column ['value'];
						}
					}
				}
			}
		}
		$select->setColumns ( $columns );
		$where = $this->_getWhereForLocale();
		$select->setParentId ( $params ['id'] );
		$data = $select->getData ($where);
		$data = $this->prepareData ( $data, $attribColumns );
		return $data; 
	}
	
	private function _createNode() {
		$params = $this->params;
		$model = $this->model;
		$types = $model->getTypes ();
		if (! isset ( $params ['type'] )) {
			throw new Zend_Exception ( 'Dont set type parametr' );
		}
		
		$form_options['attribs'] = $this->_getFormAttribs();
		$form_name = $types [$params ['type']] ['form'];
		$form = new $form_name ($form_options);
		
		$title = 'Добавить ' . $types [$params ['type']] ['label'];
		$controler = $this->getActionController();
		
		if ($controler->getRequest ()->isPost () && $form->isValid ( $params )) {
			$formParams = $form->getValues ();
			//Если несколько субформ
			if (sizeof ( $form->getSubForms () ) > 0) {
				$data = array ();
				foreach ( $form->getSubForms () as $subform ) {
					$data = array_merge ( $data, $formParams [$subform->getName ()] );
				}
				$formParams = $data;
			}
			$meta_params = $this->_getMetaParams($params);
			$formParams = array_merge($formParams,$meta_params);
			$id = $model->create ( $formParams );
			$this->log('Creating ' . $id . ' ' . $types [$params ['type']] ['label']);
			$data = array ('status' => true, 'id' => $id, 'label' => $params ['label'] );

			$controler->getHelper('flashMessenger')->setNamespace ( 'messages' )->addMessage ( array ('text' => 'Добавление выполнено успешно', 'type' => $type ) );
			$module_name = $this->getRequest()->getModuleName();
			$controler_name = $this->getRequest()->getControllerName();
			$controler->getHelper('redirector')->gotoRoute(array('module'=>$module_name,'controller'=>$controler_name,'action'=>'index'),'backend');

		} else {
			$controler->view->title = $title;
			$controler->view->form = $form;
			$view = $types [$params ['type']] ['view'];
			$controler->render ( $view );
		}
	}
	
	private function _getWhereForLocale() {
		$params = $this->params;
		$where = null;
		$parent_id = $params ['id'];
		$cfg = Zend_Registry::get ( 'cnf' );
		if ($cfg->languages->multiLang) {
			$model = new Locale_Model_List();	
			$locale_list = $model->getList();
			foreach ($locale_list as $item) {
				if ( $item['alias'] == $parent_id ) {
					$where = "locale='$parent_id'";
				}
			}
			$parent_id = 0;
		}
		return $where;
	}
	
	private function _getFormAttribs() {
		$params = $this->params;
		//Передача параметра parent_id в форму для валидации
		$parent_id = $params ['parent_id'];
		$result = array();
		$cfg = Zend_Registry::get ( 'cnf' );
		if ($cfg->languages->multiLang) {
			$model = new Locale_Model_List();	
			$locale_list = $model->getList();
			foreach ($locale_list as $item) {
				if ( $item['alias'] == $parent_id ) {
					$result['locale'] = $parent_id;
				}
			}
			$result['parent_id'] = 0;
		}
		if (! isset($result['parent_id'])) {
			$parent_id = trim ( preg_replace ( '/\D/ui', '', $parent_id ) );
			if ( $parent_id == '' ) 
				throw new Zend_Exception ( 'Dont set parent_id parametr' );
			$result['parent_id'] = $parent_id;
		}
		$result['id'] = null;
		return $result; 
	}
	
	/**
	 * 
	 * Getting meta-params type, parent_id, locale
	 * @param request params
	 * @throws Exception 
	 * TODO validate parent_id, type
	 */
	private function _getMetaParams($params) {
		$result = array();
		$result['type'] = $params ['type']; 
		$locale = null;
		$parent_id = $params ['parent_id'];
		$cfg = Zend_Registry::get ( 'cnf' );
		$model = $this->model;
		if ( $cfg->languages->multiLang && $model->getMultilang() ) {
			$locale_model = new Locale_Model_List();	
			$locale_list = $locale_model->getList();
			foreach ($locale_list as $item) {
				if ( $item['alias'] == $parent_id ) {
					$locale = $parent_id;
				}
			}
			if ($locale) {
				$result['locale'] = $parent_id;
				$result['parent_id'] = 0;
			} else {
				$parent_id = trim ( preg_replace ( '/\D/ui', '', $parent_id ) );
				$res = $model->getBranch("id=$parent_id");
				if (! $res) {
					throw new Exception('There is no root node');
				}
				$result['locale'] = $res[0]['locale'];
			}
		}
		$result['parent_id'] = $parent_id;
		return $result; 
	}
	
}
